{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7c647f7a-d848-4139-9469-5c6529bd5510",
   "metadata": {},
   "source": [
    "FastAPI 提供了简单易用，但功能强大的依赖注入系统。\r\n",
    "\r\n",
    "这个依赖系统设计的简单易用，可以让开发人员轻松地把组件集成至 FastAP\n",
    "\n",
    "什么是「依赖注入」\n",
    "\n",
    "编程中的「依赖注入」是声明代码（本文中为路径操作函数 ）运行所需的，或要使用的「依赖」的一种方式。\r\n",
    "\r\n",
    "然后，由系统（本文中为 FastAPI）负责执行任意需要的逻辑，为代码提供这些依赖（「注入」依赖项）。\r\n",
    "\r\n",
    "依赖注入常用于以下场景：\r\n",
    "\r\n",
    "共享业务逻辑（复用相同的代码逻辑）\r\n",
    "共享数据库连接\r\n",
    "实现安全、验证、角色权限\r\n",
    "等……\r\n",
    "上述场景均可以使用依赖注入，将代码重复最小化。I。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "886e0da9-9e61-45e1-8221-01aa2414c27d",
   "metadata": {},
   "source": [
    "创建依赖项\r\n",
    "首先，要关注的是依赖项。\r\n",
    "\r\n",
    "依赖项就是一个函数，且可以使用与路径操作函数相同的\n",
    "\n",
    "声明依赖项\n",
    "与在路径操作函数参数中使用 Body、Query 的方式相同，声明依赖项需要使用 Depends 和一个新的参数：\n",
    "参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "510ab3d9-4288-4388-9a02-e647bbe5e248",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Started server process [22264]\n",
      "INFO:     Waiting for application startup.\n",
      "INFO:     Application startup complete.\n",
      "INFO:     Uvicorn running on http://0.0.0.0:8009 (Press CTRL+C to quit)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:     127.0.0.1:53912 - \"GET /items/?q=%E5%BC%A0%E4%B8%89 HTTP/1.1\" 200 OK\n",
      "INFO:     127.0.0.1:53925 - \"GET /users/?q=%E6%9D%8E%E5%9B%9B HTTP/1.1\" 200 OK\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Shutting down\n",
      "INFO:     Waiting for application shutdown.\n",
      "INFO:     Application shutdown complete.\n",
      "INFO:     Finished server process [22264]\n"
     ]
    }
   ],
   "source": [
    "import uvicorn\n",
    "from fastapi import Depends, FastAPI\n",
    "app = FastAPI()\n",
    "\n",
    "async def common_parameters(\n",
    "    q: str | None = None, skip: int = 0, limit: int = 100\n",
    "):\n",
    "    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n",
    "\n",
    "\n",
    "@app.get(\"/items/\")\n",
    "async def read_items(commons: dict = Depends(common_parameters)):\n",
    "    return commons\n",
    "\n",
    "\n",
    "@app.get(\"/users/\")\n",
    "async def read_users(commons: dict = Depends(common_parameters)):\n",
    "    return commons\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    config = uvicorn.Config(app, host='0.0.0.0', port=8009)\n",
    "    server = uvicorn.Server(config)\n",
    "    await server.serve()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74135213-4aa0-4458-95c5-5635494306cf",
   "metadata": {},
   "source": [
    "依赖注入无非是与路径操作函数一样的函数罢了。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "442dc199-51aa-4f9e-b57d-55900e18ee40",
   "metadata": {},
   "source": [
    "大功告成。\r\n",
    "\r\n",
    "只用了2 行代码。\r\n",
    "\r\n",
    "依赖项函数的形式和结构与路径操作函数一样。\r\n",
    "\r\n",
    "因此，可以把依赖项当作没有「装饰器」（即，没有 @app.get(\"/some-path\") ）的路径操作函数。\r\n",
    "\r\n",
    "依赖项可以返回各种内容。\r\n",
    "\r\n",
    "本例中的依赖项预期接收如下参数：\r\n",
    "\r\n",
    "类型为 str 的可选查询参数 q\r\n",
    "类型为 int 的可选查询参数 skip，默认值是 0\r\n",
    "类型为 int 的可选查询参数 limit，默认值是 100\r\n",
    "然后，依赖项函数返回包含这些值的 dict。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cca35809-b580-4cac-999d-8a5e0005a2fb",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'http://127.0.0.1:8009/items/?q=张三' \n",
    "res = requests.get(url) \n",
    "res.text\n",
    "\n",
    "# 在另一个ipynb文件中运行代码，会得到 '{\"q\":\"张三\",\"skip\":0,\"limit\":100}'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb13ea2f-d75f-4a52-a5b0-4fb327d89c82",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'http://127.0.0.1:8009/users/?q=李四' \n",
    "res = requests.get(url) \n",
    "res.text\n",
    "\n",
    "# 在另一个ipynb文件中运行代码，会得到 '{\"q\":\"李四\",\"skip\":0,\"limit\":100}'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13431518-f7cd-435a-91c7-15aaba056caf",
   "metadata": {},
   "source": [
    "虽然，在路径操作函数的参数中使用 Depends 的方式与 Body、Query 相同，但 Depends 的工作方式略有不同。\r\n",
    "\r\n",
    "这里只能传给 Depends 一个参数。\r\n",
    "\r\n",
    "且该参数必须是可调用对象，比如函数。\r\n",
    "\r\n",
    "该函数接收的参数和路径操作函数的参接收到新的请求时，FastAPI 执行如下操作：\r\n",
    "\r\n",
    "用正确的参数调用依赖项函数（「可依赖项」）\r\n",
    "获取函数返回的结果\r\n",
    "把函数返回的结果赋值给路径操作函\n",
    "\n",
    "这样，只编写一次代码，FastAPI 就可以为多个路径操作共享这段代码 。数的参数数一样。\n",
    "\n",
    "："
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5cd3827e-4f04-478e-9b9b-d9af64f0583e",
   "metadata": {},
   "source": [
    "虽然，层级式依赖注入系统的定义与使用十分简单，但它却非常强大。\r\n",
    "\r\n",
    "比如，可以定义依赖其他依赖项的依赖项。\r\n",
    "\r\n",
    "最后，依赖项层级树构建后，依赖注入系统会处理所有依赖项及其子依赖项，并为每一步操作提供（注入）结果。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
